﻿/**
 * @file file.c
 * @date 23.5.7
 * @author yrz
 * @brief 文件相关数据结构和函数
 * @version 0.1
 * @status Stable

**/

#include "types.h"
#include "fs.h"
#include "file.h"
#include "riscv.h"
#include "defs.h"
#include "param.h"
//#include "spinlock.h"
//#include "sleeplock.h"

#include "stat.h"
#include "proc.h"
struct devsw devsw[NDEV];

struct {
    //struct spinlock lock;
    struct file file[NFILE];
} ftable;


void
fileinit(void)
{
    //initlock(&ftable.lock, "ftable");
}

/**
 * @brief 分配文件结构
 * @return 指向文件的指针
*/
struct file*
    filealloc(void)
{
    struct file* f;

    //acquire(&ftable.lock);
    for (f = ftable.file; f < ftable.file + NFILE; f++) {
        if (f->ref == 0) {
            f->ref = 1;
            //release(&ftable.lock);
            return f;
        }
    }
    //release(&ftable.lock);
    return 0;
}


/**
 * @brief 增加文件f的引用计数值
 * @param f 文件
*/
struct file*
    filedup(struct file* f)
{
    //acquire(&ftable.lock);
    if (f->ref < 1)
        panic("filedup");
    f->ref++;
    //release(&ftable.lock);
    return f;
}


/**
 * @brief 关闭文件；若引用数不为0，则减少引用数，否则关闭
 * @param f 文件
*/
void
fileclose(struct file* f)
{
    struct file ff;

    //acquire(&ftable.lock);
    if (f->ref < 1)
        panic("fileclose");
    if (--f->ref > 0) {
        //release(&ftable.lock);
        return;
    }
    ff = *f;
    f->ref = 0;
    f->type = FD_NONE;
    //release(&ftable.lock);

    if (ff.type == FD_PIPE) {
        // pipeclose(ff.pipe, ff.writable);
    }
    else if (ff.type == FD_INODE || ff.type == FD_DEVICE) {
        begin_op();
        iput(ff.ip);
        end_op();
    }
}


/**
 * @brief 获取文件的元数据
 * @param f 文件
 * @param addr 用户虚拟地址，指向stat结构
*/
int
filestat(struct file* f, uint64 addr)
{
    struct proc* p = myproc();
    struct stat st;

    if (f->type == FD_INODE || f->type == FD_DEVICE) {
        //ilock(f->ip);
        stati(f->ip, &st);
        //iunlock(f->ip);
        if (copyout(p->pagetable, addr, (char*)&st, sizeof(st)) < 0)
            return -1;
        return 0;
    }
    return -1;
}

// Read from file f.
// addr is a user virtual address.
/**
 * @brief 读文件f
 * @param f 文件
 * @param addr 用户虚拟地址
 * @param n 读取字节数
*/
int
fileread(struct file* f, uint64 addr, int n)
{
    int r = 0;

    if (f->readable == 0)
        return -1;

	/*if (f->type == FD_PIPE) {
		r = piperead(f->pipe, addr, n);
	}*/
    if (f->type == FD_DEVICE) {
        if (f->major < 0 || f->major >= NDEV || !devsw[f->major].read)
            return -1;
        r = devsw[f->major].read(1, addr, n);
    }
    else if (f->type == FD_INODE) {
        //ilock(f->ip);
        if ((r = readi(f->ip, 1, addr, f->off, n)) > 0)
            f->off += r;
        //iunlock(f->ip);
    }
    else {
        panic("fileread");
    }

    return r;
}

// Write to file f.
// addr is a user virtual address.
/**
 * @brief 写文件f
 * @param f 文件
 * @param addr 用户虚拟地址
 * @param n 写字节数
*/
int
filewrite(struct file* f, uint64 addr, int n)
{
    int r, ret = 0;

    if (f->writable == 0)
        return -1;

    /*if (f->type == FD_PIPE) {
        ret = pipewrite(f->pipe, addr, n);
    }*/
    if (f->type == FD_DEVICE) {
        if (f->major < 0 || f->major >= NDEV || !devsw[f->major].write)
            return -1;
        ret = devsw[f->major].write(1, addr, n);
    }
    else if (f->type == FD_INODE) {
       
        // 一次写几个块以避免超过最大日志事务大小，包括i-node、
        // 间接块、分配块和2块非对齐写入的slop块。这实际上属于
        // 底层，因为writei()可能正在写console。
        int max = ((MAXOPBLOCKS - 1 - 1 - 2) / 2) * BSIZE;
        int i = 0;
        while (i < n) {
            int n1 = n - i;
            if (n1 > max)
                n1 = max;

            begin_op();
            ilock(f->ip);
            if ((r = writei(f->ip, 1, addr + i, f->off, n1)) > 0)
                f->off += r;
            iunlock(f->ip);
            end_op();

            if (r != n1) {
                //  writei发生错误
                break;
            }
            i += r;
        }
        ret = (i == n ? n : -1);
    }
    else {
        panic("filewrite");
    }

    return ret;
}